var languages = ( function() {

    var Storage = ( function() {

        function Storage(fs, rootFolder, potentialSessionId) {
            this.mFileSystem    = fs;
            this.mRootFolder = "";
            this.mManifests  = {};
            if (fs.global) {
                this.mManifests.global = {
                    fs : fs.global
                }
            }
            var personalManifest = {
                sessionId       : potentialSessionId ? potentialSessionId : new Date().getTime()
            };
            if (fs.remote && fs.local) {
                this.mManifests.personalRemote = {
                    fs          : fs.remote
                }
                this.mManifests.personal = {
                    fs          : fs.local,
                    manifest    : personalManifest
                }
            } else if (fs.remote || fs.local) {
                this.mManifests.personal = {
                    fs          : fs.local ? fs.local : fs.remote,
                    manifest    : personalManifest
                }
            }

            if (rootFolder) {
                this.mRootFolder = rootFolder;
            }
        }

        Storage.prototype.path = function(path) {
            return this.mRootFolder+path;
        }

        Storage.prototype.init = function() {
            var self = this;
            return createFolders(this)
            .pipe(function() {
                return collectManifests(self);
            });
        }

        function createFolders(self) {
            if (self.mFileSystem.remote) {
                return self.mFileSystem.remote.exists(self.mRootFolder)
                .then(function(exists) {
                    if (!exists) {
                        return self.mFileSystem.remote.mkdir(self.mRootFolder);
                    }
                });
            }
            return $.Deferred().resolve().promise();
        }

        function collectManifests(self) {
            var manifestPath = self.path("manifest.json");

            function loadManifest(manifestTypeName) {
                var manifestType = self.mManifests[manifestTypeName];
                return self.readFile(manifestPath, manifestType.fs)
                .then(function(jsonData) {
                    manifestType.manifest = jsonData;
                })
                .fail(function(error) {
                    console.log(""+error);
                    if (!error.notFound) {
                        delete self.mManifests[manifestTypeName];
                    }
                });
            }

            var tasks = [];
            for (var manifestType in self.mManifests) {
                tasks.push(loadManifest(manifestType));
            }
            return when.all(tasks);
        }

        Storage.prototype.readFile = function(path, fileSystem) {
            var result = $.Deferred();

            try {
                $.when(fileSystem.read(path))
                .then(function(data) {
                    result.resolve(JSON.parse(data));
                })
                .fail(function(error) {
                    error.message = "When reading '"+path+"' from file system '"+fileSystem.name()+"': "+error.message;
                    result.reject(error);
                });
            } catch (error) {
                error.message = "When reading '"+path+"' from file system '"+fileSystem.name()+"': "+error.message;
                result.reject(error);
            }

            return result.promise();
        }

        return Storage;
    })();










    var Languages = ( function() {

        function Languages(fs) {
            this.mFileSystem = fs;
            this.mLanguages = {};
            Storage.call(this, fs);
        }
        Languages.prototype.__proto__ = Storage.prototype;

        Languages.prototype.init = function() {
            var result = $.Deferred();
            var self = this;
            Storage.prototype.init.call(this)
            .then(function() {
                if (self.mManifests.personal) {
                    for (var langName in self.mManifests.personal.manifest.languages) {
                        self.mLanguages[langName] = new language.Language(self, self.mManifests.personal.manifest.languages[langName]);
                    }
                }
                if (self.mManifests.personalRemote && self.mManifests.personalRemote.manifest) {
                    for (var langName in self.mManifests.personalRemote.manifest.languages) {
                        if (!(langName in self.mLanguages)) {
                            self.mLanguages[langName] = new language.Language(self, self.mManifests.personalRemote.manifest.languages[langName]);
                        }
                    }
                }
                if (self.mManifests.global && self.mManifests.global.manifest) {
                    for (var langName in  self.mManifests.global.manifest.languages) {
                        if (!(langName in self.mLanguages)) {
                            self.mLanguages[langName] = new language.Language(self, self.mManifests.global.manifest.languages[langName]);
                        }
                    }
                }
                var initTasks = [];
                for (var langName in self.mLanguages) {
                    initTasks.push(self.mLanguages[langName].init());
                }
                return when.all(initTasks);
            })
            .then(function() {
                result.resolve();
            });
            return result.promise();
        }

        Languages.prototype.languages = function(name) {
            return this.mLanguages;
        }

        Languages.prototype.sessionId = function() {
            return this.mManifests.personal.manifest.sessionId;
        }

        return Languages;
    })();

    return {
        Languages : Languages,
        Storage   : Storage
    }
})();



//for node based tests
if (typeof window === 'undefined') {
    module.exports = languages;
}